// 2-1 模板-函数模板

/**
 * C++ 模板
 * 模板是**泛型编程**的基础，泛型编程即以一种独立于任何特定类型的方式编写代码。

 * 模板是创建泛型类或函数的蓝图或公式。库容器，比如**迭代器**和**算法**，都是泛型编程的例子，它们都使用了模板的概念。

 * 每个容器都有一个单一的定义，比如 向量，我们可以定义许多不同类型的向量，比如 vector <int> 或 vector <string>。

 * 您可以使用模板来定义**函数和类**，接下来让我们一起来看看如何使用。

 *-------------------------
 * 函数模板
 * 模板函数定义的一般形式如下所示：

          template <typename type> ret-type func-name(parameter list)
          {
            // 函数的主体
          }

 * 在这里，type 是函数所使用的**数据类型的占位符名称**。这个名称可以在函数定义中使用。

 * 下面是函数模板的实例（实例一），返回两个数中的最大值：
 *
 * 
 * #1 实例一
 * #2 测试多个 typename
 * #3 测试用 template <class T> 创建模板函数
 * #4 模板函数定义、声明分离
*/
#include <iostream>
#define __mark 2
/**
 * #1 实例一
*/
#if 1 == __mark
template <typename T>
inline T const &max(T &a, T &b)
{
  return a > b ? a : b;
}

int main(void)
{
  int i1 = 1;
  int i2 = 2;
  // std::cout << "max(1,2)" << max(1, 2) << std::endl;// error: cannot bind non-const lvalue reference of type 'double&' to an rvalue of type 'double'
  std::cout << "max(1,2) : " << max(i1, i2) << std::endl;

  double d1 = 2.1;
  double d2 = 3.1;
  // std::cout << "max(2.1,3.1)" << max(2.1, 3.1) << std::endl;
  std::cout << "max(2.1,3.1) : " << max(d1, d2) << std::endl;

  std::string str1 = "Hello";
  std::string str2 = "World";

  std::cout << "max(\"Hello\",\"World\") : " << max(str1, str2) << std::endl;

  // max(i1, i2) += 10; // 函数返回值为引用时，如果不想数据被修改，可以加const修饰
  // std::cout << "i2 : " << i2 << std::endl;
  printf("-----------------end------------------\n");
  return 0;
}

/**
 * #2 测试多个 typename
*/
#elif 2 == __mark
template <typename T, typename X, typename Y>
inline T const &max(T &a, T &b, X c = 0, Y d = false)
{
  std::cout << "a : " << a << " b : " << b << " c : " << c << " d : " << d << std::endl;
  if (c)
  {
    // return (double)c;
    static T temp = c;
    return temp;
  }
  return a > b ? a : b;
}

int main(void)
{
  int i1 = 1;
  int i2 = 2;
  // std::cout << "max(1,2)" << max(1, 2) << std::endl;// error: cannot bind non-const lvalue reference of type 'double&' to an rvalue of type 'double'
  // std::cout << "max(1,2) : " << max(i1, i2) << std::endl;

  double d1 = 2.1;
  double d2 = 3.1;
  // std::cout << "max(2.1,3.1)" << max(2.1, 3.1) << std::endl;
  // std::cout << "max(2.1,3.1) : " << max(d1, d2) << std::endl;

  std::string str1 = "Hello";
  std::string str2 = "World";

  std::cout << "max(\"Hello\",\"World\") : " << max(str1, str2) << std::endl;

  // std::cout << "test : " << max(i1, i2, d1) << std::endl;
  // std::cout << "test : " << max(i1, i2, d1, str1) << std::endl;

  // max(i1, i2) += 10; // 函数返回值为引用时，如果不想数据被修改，可以加const修饰
  // std::cout << "i2 : " << i2 << std::endl;
  printf("-----------------end------------------\n");
  return 0;
}

/**
 * #3 测试用 template <class T> 创建模板函数
*/
#elif 3 == __mark
template <class T>
inline T const &max(T &a, T &b)
{
  return a > b ? a : b;
}

int main(void)
{
  int i1 = 1;
  int i2 = 2;
  // std::cout << "max(1,2)" << max(1, 2) << std::endl;// error: cannot bind non-const lvalue reference of type 'double&' to an rvalue of type 'double'
  std::cout << "max(1,2) : " << max(i1, i2) << std::endl;

  double d1 = 2.1;
  double d2 = 3.1;
  // std::cout << "max(2.1,3.1)" << max(2.1, 3.1) << std::endl;
  std::cout << "max(2.1,3.1) : " << max(d1, d2) << std::endl;

  std::string str1 = "Hello";
  std::string str2 = "World";

  std::cout << "max(\"Hello\",\"World\") : " << max(str1, str2) << std::endl;

  // max(i1, i2) += 10; // 函数返回值为引用时，如果不想数据被修改，可以加const修饰
  // std::cout << "i2 : " << i2 << std::endl;
  printf("-----------------end------------------\n");
  return 0;
}

/**
 * #4 模板函数定义、声明分离
*/
#elif 4 == __mark
template <class T1, class T2>
void test(T1, T2);
int main(void)
{
  test(123, "hhh");
  printf("———————————end———————————\n");
  return 0;
}
template <class T1, class T2>
void test(T1 a, T2 b)
{
  std::cout << "a : " << a << std::endl;
  std::cout << "b : " << b << std::endl;
}
#endif